package com.heima.article.job;
import com.alibaba.fastjson.JSON;
import com.heima.article.service.HotArticleService;
import com.heima.common.article.HotArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.app.AggBehaviorDTO;
import com.heima.model.mess.app.NewBehaviorDTO;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class UpdateHotArticleJob {
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    HotArticleService hotArticleService;

    @XxlJob("updateHotArticleJob")
    public ReturnT updateHotArticleHandler(String params){
        log.info("热文章分值更新 调度任务开始执行....");
        // 1. 从redis中获取最近10s所产生的行为数据
        List<NewBehaviorDTO> newBehaviorDTOList = getRedisBehaviorList();
        if (CollectionUtils.isEmpty(newBehaviorDTOList)) {
            log.info(" 太冷清了，最近10s钟没人操作我们的项目");
            return ReturnT.SUCCESS;
        }
        // 2. 对数据进行聚合处理
        List<AggBehaviorDTO> aggBehaviorList = getAggBehaviorList(newBehaviorDTOList);
        if(CollectionUtils.isEmpty(aggBehaviorList)){
            log.info(" 太冷清了，最近10s钟没人操作我们的项目");
            return ReturnT.SUCCESS;
        }
        // 3. 根据聚合处理的结果,修改文章的热度，更新热点文章缓存
//        aggBehaviorList.forEach(aggBehaviorDTO -> {
//            hotArticleService.updateApArticle(aggBehaviorDTO);
//        });
        aggBehaviorList.forEach(hotArticleService::updateApArticle);
        // TODO 定时更新文章热度
        log.info("热文章分值更新 调度任务完成....");
        return ReturnT.SUCCESS;
    }

    /**
     * 聚合处理行为结果
     * @param newBehaviorDTOList
     * @return
     */
    private List<AggBehaviorDTO> getAggBehaviorList(List<NewBehaviorDTO> newBehaviorDTOList) {
        // 1. 先按照文章id进行分组
        Map<Long, List<NewBehaviorDTO>> map = newBehaviorDTOList.stream()
                .collect(Collectors.groupingBy(NewBehaviorDTO::getArticleId));
        // 2. 遍历分组map  Map<文章id, List<NewBehaviorDTO>>
        ArrayList<AggBehaviorDTO> aggBehaviorDTOS = new ArrayList<>();
        map.forEach((articleId,newBehaviorList)->{
            //    将每一个分组 下的 newBehavior集合  聚合处理为 一个 AggBehaviorDTO对象
            Optional<AggBehaviorDTO> reduceResult = newBehaviorList.stream()
                    .map(newBehavior -> {
                        AggBehaviorDTO aggBehaviorDTO = new AggBehaviorDTO();
                        aggBehaviorDTO.setArticleId(articleId);
                        switch (newBehavior.getType()) {
                            case VIEWS:
                                aggBehaviorDTO.setView(newBehavior.getAdd());
                                break;
                            case COLLECTION:
                                aggBehaviorDTO.setCollect(newBehavior.getAdd());
                                break;
                            case LIKES:
                                aggBehaviorDTO.setLike(newBehavior.getAdd());
                                break;
                            case COMMENT:
                                aggBehaviorDTO.setComment(newBehavior.getAdd());
                                break;
                        }
                        return aggBehaviorDTO;
                    }).reduce((a1, a2) -> {
                        a1.setView(a1.getView() + a2.getView());
                        a1.setLike(a1.getLike() + a2.getLike());
                        a1.setComment(a1.getComment() + a2.getComment());
                        a1.setCollect(a1.getCollect() + a2.getCollect());
                        return a1;
                    });
            aggBehaviorDTOS.add(reduceResult.get());
        });
        return aggBehaviorDTOS;
    }

    /**
     * 从redis中 获取数据
     * @return
     */
    private List<NewBehaviorDTO> getRedisBehaviorList() {
        // 1. 定义lua脚本配置
        try {
            DefaultRedisScript<List> script = new DefaultRedisScript<>();
            script.setResultType(List.class);
            script.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis.lua")));
            // 2. 使用redis执行lua脚本
            List<String> behaviorJsonList = redisTemplate.execute(script, Arrays.asList(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST));
            return behaviorJsonList.stream()
                            .map(behaviorJson-> JSON.parseObject(behaviorJson,NewBehaviorDTO.class))
                            .collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"redis执行lua脚本出错");
            return null;
        }
    }
}